package com.hhh.springai_test.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hhh.springai_test.common.ErrorCode;
import com.hhh.springai_test.constant.CommonConstant;
import com.hhh.springai_test.constant.RegexConstant;
import com.hhh.springai_test.constant.UserConstant;
import com.hhh.springai_test.exception.BusinessException;
import com.hhh.springai_test.mapper.UserMapper;
import com.hhh.springai_test.model.dto.user.UserQueryRequest;
import com.hhh.springai_test.model.enums.GenderEnum;
import com.hhh.springai_test.model.po.User;
import com.hhh.springai_test.saToken.DeviceUtils;
import com.hhh.springai_test.service.UserService;
import com.hhh.springai_test.utils.NetUtils;
import com.hhh.springai_test.utils.SqlUtils;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.Map;
import java.util.regex.Pattern;

@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {


    private final String SALT = "xg";

    /**
     * 实现注册功能
     * @param email 用户邮箱
     * @param username 用户名
     * @param password 密码
     * @param request HTTP请求对象，用于获取用户IP地址
     * @return 注册结果，true表示成功，false表示失败
     */
    @Override
    public Boolean register(String email, String username, String password, HttpServletRequest request) {

        // 编译邮箱正则表达式，用于后续匹配验证
        Pattern compile = Pattern.compile(RegexConstant.EMAIL_REGEX);
        // 验证邮箱格式是否正确
        if (!compile.matcher(email).matches()) {
            // 如果邮箱格式不正确，抛出业务异常
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"邮箱格式不正确");
        }
        // 验证用户名长度是否在规定范围内
        if (!username.matches(RegexConstant.usernameRegex)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户名格式不正确，只能包含大小写字母、数字和点");
        }
        //验证密码
        if(password.length() < 6 || password.length() > 18){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"密码长度应该在6-18位之间");
        }
        synchronized (email.intern()) {
            //验证邮箱
            QueryWrapper<User> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("email",email);
            User emailUser = this.getOne(queryWrapper);
            if(emailUser != null ){
                throw new BusinessException(ErrorCode.PARAMS_ERROR,"邮箱已存在");
            }
            //验证用户名
            QueryWrapper<User> queryWrapperUserName = new QueryWrapper<>();
            queryWrapperUserName.eq("username",username);
            User userNameUser = this.getOne(queryWrapperUserName);
            if(userNameUser != null ){
                throw new BusinessException(ErrorCode.PARAMS_ERROR,"用户名已存在");
            }
            //生成新的密码
            password = SecureUtil.md5(password + SALT);
            User user = new User();
            user.setEmail(email);
            user.setUsername(username);
            user.setPassword(password);
            user.setGender(GenderEnum.MALE.getCode());
            user.setAvatarUrl(UserConstant.AVATAR_PATH);
            user.setNickName(UserConstant.DEFAULT_NAME);
            user.setUserProfile(UserConstant.DEFAULT_PROFILE);
            // 获取用户IP地址
            String ip = NetUtils.getIpAddress(request);
            // 将IP地址转换为实际地理位置
            Map<String, String> toIpAddress = NetUtils.getToIpAddress(ip);
            String address = toIpAddress.get("city");
            user.setAddress(address);
            // 保存用户信息
            boolean save = this.save(user);
            if(!save){
                throw new BusinessException(ErrorCode.REGISTER_ERROR,"注册失败，数据库发生错误");
            }
            return save;
        }
    }


    /**
     * 登录功能实现
     *
     * @param username 用户名，用于查询用户信息
     * @param password 密码，用于验证用户身份
     * @param request HTTP请求对象，可用于获取请求相关的信息
     * @return 登录成功返回true，否则抛出异常
     *
     * 此方法首先根据用户名查询用户信息，如果用户不存在，则抛出异常
     * 接着对密码进行MD5加密处理，并再次查询用户信息以验证密码的正确性
     * 如果密码错误，则抛出异常
     * 最后，使用StpUtil进行登录操作，表示用户登录成功
     */
    @Override
    public Boolean login(String username, String password, HttpServletRequest request) {
        // 根据用户名查询用户信息
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username",username);
        User loginUser = this.getOne(queryWrapper);
        if(loginUser == null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"此账号不存在，请注册之后在登录");
        }

        // 对输入的密码进行MD5加密处理
        password = SecureUtil.md5(password + SALT);

        // 验证加密后的密码是否正确
        queryWrapper.eq("password",password);
        User newUser = this.getOne(queryWrapper);
        if(newUser == null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"密码输入错误，请重新输入");
        }

        // 使用StpUtil进行登录操作
        StpUtil.login(newUser.getId(), DeviceUtils.getRequestDevice(request));
        StpUtil.getSession().set(UserConstant.USER_LOGIN_STATE,newUser);
        return true;
    }


    /**
     * 重写更新用户密码的方法
     *
     * @param oldPassword 用户输入的旧密码
     * @param password 用户输入的新密码
     * @param email 用户的邮箱地址，用于验证和定位用户
     * @return 如果密码修改成功，则返回true；否则返回false
     * @throws BusinessException 当邮箱或旧密码输入错误，或修改密码失败时抛出业务异常
     */
    @Override
    public Boolean updatePassword(String oldPassword, String password, String email) {
        // 创建查询条件，根据邮箱地址查询用户
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("email",email);
        User user = this.getOne(queryWrapper);
        // 如果用户不存在，则抛出异常提示邮箱输入错误
        if(user == null ){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"邮箱号输入错误");
        }
        // 更新查询条件，根据旧密码查询用户
        queryWrapper.eq("password",SecureUtil.md5(oldPassword + SALT));
        User newUser = this.getOne(queryWrapper);
        // 如果旧密码不匹配，则抛出异常提示旧密码输入错误
        if(newUser == null ){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"旧密码输入错误");
        }
        // 对新密码进行加密处理
        password = SecureUtil.md5(password + SALT);
        // 同步代码块，确保并发安全
        synchronized (email.intern()){
            // 更新用户的新密码
            newUser.setPassword(password);
            // 保存更新后的用户信息
            boolean save = this.updateById(newUser);
            // 如果保存失败，则抛出异常提示修改密码失败
            if(!save){
                throw new BusinessException(ErrorCode.PARAMS_ERROR,"修改密码失败");
            }
            // 返回保存结果
            return save;
        }
    }

    /**
     * 更新用户信息的方法
     *
     * @param wxCode 微信号，长度限制为40字符以内
     * @param nickName 用户昵称，长度限制为255字符以内
     * @param phone 用户手机号，需符合邮箱格式
     * @param gender 用户性别，仅接受男性或女性的代码
     * @param userProfile 用户简介，长度限制为255字符以内
     * @param loginUserId 当前登录用户的ID
     * @return 更新操作的布尔结果
     * @throws BusinessException 当输入参数不符合规范时抛出业务异常
     */
    @Override
    public Boolean updateUserInfo(String wxCode, String nickName,String avatarUrl, String phone, Integer gender, String userProfile,String loginUserId) {
        // 获取当前登录用户的信息
        User user = this.getById(loginUserId);
        // 验证微信号长度是否超过40
        if(wxCode.length() >= 40){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"微信号长度不能超过40");
        }
        // 验证昵称长度是否超过255
        if(nickName.length() >= 255){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"昵称长度不能超过255");
        }
        // 验证用户简介长度是否超过255
        if(userProfile.length() >= 255 ){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"用户简介长度不能超过255");
        }
        //判断头像长度
        if(avatarUrl.length() >= 511 ){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"用户头像地址不合法");
        }
        // 验证性别参数是否正确
        if(!gender.equals(GenderEnum.MALE.getCode()) && !gender.equals(GenderEnum.FEMALE.getCode())){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"性别参数错误");
        }
        // 编译正则表达式以验证手机号格式
        Pattern compile = Pattern.compile(RegexConstant.regex);
        // 验证邮箱格式是否正确
        if (!compile.matcher(phone).matches()) {
            // 如果邮箱格式不正确，抛出业务异常
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"手机号格式错误");
        }
        // 更新用户信息
        user.setWXCode(wxCode);
        user.setNickName(nickName);
        user.setPhone(phone);
        user.setGender(gender);
        user.setUserProfile(userProfile);
        user.setAvatarUrl(avatarUrl);
        user.setId(Long.valueOf(loginUserId));
        // 执行更新操作
        boolean save = this.updateById(user);
        if(!save){
            // 如果更新失败，抛出业务异常
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"更新用户信息失败");
        }
        // 返回更新结果
        return save;
    }
    /**
     * 添加新用户的方法
     *
     * @param username 用户名，需要匹配特定的正则表达式
     * @param password 用户密码，长度需在6到18位之间
     * @param nickName 用户昵称，长度不能超过255
     * @param email 用户邮箱，需要符合邮箱的正则表达式
     * @param avatarUrl 用户头像的URL地址，需要符合URL的正则表达式且长度不超过512
     * @param userRole 用户角色，只能是管理员或默认用户
     * @param address 用户地址
     * @return 返回一个布尔值，表示用户是否成功添加
     * @throws BusinessException 如果参数不满足要求或用户添加失败，将抛出此异常
     */
    @Override
    public Boolean addUser(String username, String password, String nickName, String email, String avatarUrl, String userRole, String address,String phone,String wxCode) {
        // 验证昵称长度是否超过255
        if(nickName.length() >= 255){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"昵称长度不能超过255");
        }
        // 编译邮箱正则表达式，用于后续匹配验证
        Pattern compile = Pattern.compile(RegexConstant.EMAIL_REGEX);
        // 验证邮箱格式是否正确
        if (!compile.matcher(email).matches()) {
            // 如果邮箱格式不正确，抛出业务异常
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"邮箱格式不正确");
        }
        // 验证用户名长度是否在规定范围内
        if (!username.matches(RegexConstant.usernameRegex)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户名格式不正确，只能包含大小写字母、数字和点");
        }
        //验证密码
        if(password.length() < 6 || password.length() > 18){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"密码长度应该在6-18位之间");
        }
        // 对输入的密码进行MD5加密处理
        password = SecureUtil.md5(password + SALT);
        //接下来判断剩下的
        if(!UserConstant.ADMIN_ROLE.equals(userRole) && !UserConstant.DEFAULT_ROLE.equals(userRole)){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"用户角色不正确");
        }
        Pattern urlCompile = Pattern.compile(RegexConstant.UrlRegex);
        // 验证邮箱格式是否正确
        if (!urlCompile.matcher(avatarUrl).matches() || avatarUrl.length() > 512) {
            // 如果邮箱格式不正确，抛出业务异常
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"图片格式不正确或者是图片链接地址太长了");
        }
        // 编译正则表达式以验证手机号格式
        Pattern phoneCompile = Pattern.compile(RegexConstant.regex);
        // 验证手机号格式是否正确
        if (!phoneCompile.matcher(phone).matches()) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "手机号格式错误");
        }

        if (wxCode.length() > 40) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "微信号太长了");
        }
        // 创建User对象，并设置用户信息
        User user = new User();
        user.setUsername(username);
        user.setPassword(password);
        user.setNickName(nickName);
        user.setEmail(email);
        user.setPhone(phone);
        user.setWXCode(wxCode);
        user.setAvatarUrl(avatarUrl);
        // 默认设置用户性别为男性
        user.setGender(GenderEnum.MALE.getCode());
        user.setAddress(address);
        // 设置用户的个人简介为默认值
        user.setUserProfile(UserConstant.DEFAULT_PROFILE);
        user.setUserRole(userRole);
        // 保存用户信息到数据库
        boolean save = this.save(user);
        if(!save){
            // 如果用户添加失败，抛出业务异常
            throw new BusinessException(ErrorCode.REGISTER_ERROR,"新增用户失败了");
        }
        // 返回用户添加结果
        return save;
    }


    /**
     * 根据用户ID删除用户
     *
     * 当用户不存在时，抛出业务异常，指示参数错误
     * 当用户存在但删除失败时，同样抛出业务异常，指示删除操作失败
     *
     * @param userId 用户ID，用于标识要删除的用户
     * @return 返回删除操作的结果，true表示删除成功
     * @throws BusinessException 如果用户不存在或删除失败，抛出此异常
     */
    @Override
    public Boolean removeUserId(String userId) {
        // 根据用户ID获取用户对象
        User user = this.getById(userId);
        // 检查用户是否存在
        if(user == null ){
            // 如果用户不存在，抛出业务异常
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"用户不存在");
        }
        // 执行删除操作
        boolean removeById = this.removeById(userId);
        // 检查删除操作是否成功
        if(!removeById){
            // 如果删除失败，抛出业务异常
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"删除用户失败");
        }
        // 返回删除操作的结果
        return removeById;
    }

    @Override
    public Wrapper<User> getQueryWrapper(UserQueryRequest userQueryRequest) {
        String id = userQueryRequest.getId();
        String username = userQueryRequest.getUsername();
        String email = userQueryRequest.getEmail();
        String address = userQueryRequest.getAddress();
        String userRole = userQueryRequest.getUserRole();
        String gender = userQueryRequest.getGender();
        String createTime = userQueryRequest.getCreateTime();
        String updateTime = userQueryRequest.getUpdateTime();
        String wxCode = userQueryRequest.getWxCode();
        String phone = userQueryRequest.getPhone();
        String sortField = userQueryRequest.getSortField();
        String sortOrder = userQueryRequest.getSortOrder();

        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        
        // 精确查询
        queryWrapper.eq(StrUtil.isNotBlank(id), "id", id);
        queryWrapper.eq(StrUtil.isNotBlank(userRole), "userRole", userRole);
        queryWrapper.eq(StrUtil.isNotBlank(gender), "gender", gender);
        queryWrapper.eq(StrUtil.isNotBlank(createTime), "createTime", createTime);
        queryWrapper.eq(StrUtil.isNotBlank(updateTime), "updateTime", updateTime);
        
        // 模糊查询
        queryWrapper.like(StrUtil.isNotBlank(username), "username", username);
        queryWrapper.like(StrUtil.isNotBlank(email), "email", email);
        queryWrapper.like(StrUtil.isNotBlank(address), "address", address);
        queryWrapper.like(StrUtil.isNotBlank(wxCode), "wxCode", wxCode);
        queryWrapper.like(StrUtil.isNotBlank(phone), "phone", phone);
        
        // 排序
        queryWrapper.orderBy(SqlUtils.validSortField(sortField), 
            sortOrder.equals(CommonConstant.SORT_ORDER_ASC), 
            sortField);
        
        return queryWrapper;
    }

    @Override
    public Boolean adminUpdateUser(String id, String password, String nickName, String email, String avatarUrl, Integer gender, String address, String phone, String wXCode, String userProfile, String userRole) {
        // 检查id是否为空
        if (StrUtil.isEmpty(id)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户id不能为空");
        }
        
        // 查询用户
        User user = this.getById(id);
        if (user == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户不存在");
        }
        
        // 验证昵称长度是否超过255
        if (nickName.length() >= 255) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "昵称长度不能超过255");
        }
        
        // 编译邮箱正则表达式，用于后续匹配验证
        Pattern compile = Pattern.compile(RegexConstant.EMAIL_REGEX);
        // 验证邮箱格式是否正确
        if (!compile.matcher(email).matches()) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "邮箱格式不正确");
        }
        
        if (!UserConstant.ADMIN_ROLE.equals(userRole) && !UserConstant.DEFAULT_ROLE.equals(userRole)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户角色不正确");
        }
        
        Pattern urlCompile = Pattern.compile(RegexConstant.UrlRegex);
        // 验证图片格式是否正确
        if (!urlCompile.matcher(avatarUrl).matches() || avatarUrl.length() > 512) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "图片格式不正确或者是图片链接地址太长了");
        }
        
        // 验证性别参数是否正确
        if (!gender.equals(GenderEnum.MALE.getCode()) && !gender.equals(GenderEnum.FEMALE.getCode())) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "性别参数错误");
        }
        
        if (address.length() > 100) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "地址长度不能超过100");
        }
        
        if (userProfile.length() > 255) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户简介不可以超过255个字");
        }
        
        // 编译正则表达式以验证手机号格式
        Pattern phoneCompile = Pattern.compile(RegexConstant.regex);
        // 验证手机号格式是否正确
        if (!phoneCompile.matcher(phone).matches()) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "手机号格式错误");
        }
        
        if (wXCode.length() > 40) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "微信号太长了");
        }

        synchronized (email.intern()) {
            // 更新用户信息
            user.setNickName(nickName);
            user.setEmail(email);
            user.setAvatarUrl(avatarUrl);
            user.setGender(gender);
            user.setAddress(address);
            user.setPhone(phone);
            user.setWXCode(wXCode);
            user.setUserProfile(userProfile);
            user.setUserRole(userRole);
            
            // 如果密码不为空，则更新密码
            if (StrUtil.isNotBlank(password)) {
                user.setPassword(SecureUtil.md5(password + SALT));
            }
            
            boolean result = this.updateById(user);
            if (!result) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "修改用户失败");
            }
            return result;
        }
    }
}
